package in.muton.edushare.pages.curricula;

import in.muton.edushare.pages.EduShareBasePage;
import in.muton.edushare.processing.objects.UnivDataHandler;
import in.muton.edushare.url.EduShareURLPanel;
import in.muton.edushare.url.URLLoader;
import in.muton.edushare.wicket.converters.choicerenderers.CourseChoiceRenderer;
import in.muton.edushare.wicket.models.CayenneList;
import in.muton.edushare.wicket.models.CayenneModel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.wicket.PageParameters;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.markup.html.CSSPackageResource;
import org.apache.wicket.markup.html.JavascriptPackageResource;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.HiddenField;
import org.apache.wicket.markup.html.form.ListChoice;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;

import com.edushare.common.constants.URLConstants;
import com.edushare.common.dao.CurriculumDAO;
import com.edushare.common.exceptions.EduShareRuntimeException;
import com.edushare.common.util.StringUtil;
import com.edushare.common.vo.Courses;
import com.edushare.common.vo.Curricula;
import com.edushare.common.vo.Departments;
import com.edushare.common.vo.Universities;

public class CurriculaEditor extends EduShareBasePage {

	private static Log log = LogFactory.getLog(CurriculaEditor.class);

	public CurriculaEditor(PageParameters params) {
		init(params);
		if (!NewCurriculaPage.isAuthorised(univModel, deptModel,
				getLoggedInUser())) {
			throw new RestartResponseException(URLLoader
					.getPageClass(URLConstants.UNAUTHORIZED_PATH));
		}
		getCourseShortList();
		add(new Label("currName", currModel.getObject().getCurriculaName()));
		add(new EduShareURLPanel("univLink", new CayenneModel<Universities>(
				currModel.getObject().getUniversity())));
		add(new Label("semNo", new Model<String>() {
			@Override
			public String getObject() {
				return Integer.toString(semesterNo + 1);
			}

			private static final long serialVersionUID = -4761461599534015247L;
		}));

		CourseChoiceRenderer ccr = new CourseChoiceRenderer(getMap());

		ListChoice<String> lmc = new ListChoice<String>("allChoices", ccr
				.getModel(), ccr.getListOfCourses(), ccr);
		lmc.setNullValid(false);

		Form<Void> f = new Form<Void>("selBox");
		f.setOutputMarkupId(true).setMarkupId("selBox");
		f.add(new PrevButton("previous"));
		f.add(new PrevButton("previous2"));
		f.add(new NextButton("next"));
		f.add(new NextButton("next2"));
		f.add(new FinishButton("finished"));
		f.add(new FinishButton("finished2"));
		f.add(lmc.setOutputMarkupId(true).setMarkupId("allChoices"));

		f.add(new HiddenField<String>("courseHiddenField",
				new PropertyModel<String>(this, "hiddenCourseList"))
				.setMarkupId("hiddenfield").setOutputMarkupId(true));
		add(f);
	}

	private void init(PageParameters params) {
		String currId = params.getString("0");
		CurriculumDAO cDAO = new CurriculumDAO(getSessionORMInterface());
		if (StringUtil.isValid(currId)) {
			Curricula curr = cDAO.getCurriculaById(Integer.parseInt(currId));
			if (curr == null)
				throw new EduShareRuntimeException("Unable to find curricula");
			currModel = new CayenneModel<Curricula>(curr);
		}
		semesterNo = params.getAsInteger("1", 0);
		deptModel = new CayenneModel<Departments>(currModel.getObject()
				.getDepartment());
		univModel = new CayenneModel<Universities>(currModel.getObject()
				.getUniversity());

		add(CSSPackageResource.getHeaderContribution(CurriculaEditor.class,
				"curricula.css"));
		add(JavascriptPackageResource.getHeaderContribution(
				CurriculaEditor.class, "parser.js"));
		add(JavascriptPackageResource.getHeaderContribution(
				CurriculaEditor.class, "curricula.js"));

	}

	@Override
	public String getPageTitle() {
		return getLoggedInUser().getCompleteUserName() + " | "
				+ currModel.getObject().getCurriculaName() + " Edit | Edushare";
	}

	@Override
	public String getUserRole() {
		return "";
	}

	private void getCourseShortList() {
		List<Courses> courseList = new ArrayList<Courses>();
		for (int i = 0; i < currModel.getObject().getTotalSemester(); i++) {
			courseList.addAll(new CurriculumDAO(getSessionORMInterface())
					.getMandatoryCourses(currModel.getObject(), i));
		}
		univCoursesList = new UnivDataHandler(new Model<Universities>(currModel
				.getObject().getUniversity())).getCourses();
		for (Courses c : courseList) {
			if (univCoursesList.contains(c)) {
				univCoursesList.remove(c);
			}
		}

		CurriculumDAO cDAO = new CurriculumDAO(getSessionORMInterface());
		courseList = cDAO
				.getMandatoryCourses(currModel.getObject(), semesterNo);
		univCoursesList.add(courseList);
		List<List<Courses>> superList = cDAO.getOptionalCourses(currModel
				.getObject(), semesterNo);
		for (List<Courses> c : superList) {
			for (Courses c1 : c) {
				if (!univCoursesList.contains(c1))
					univCoursesList.add(c1);
			}
		}
	}

	private List<IModel<Courses>> getMap() {
		List<IModel<Courses>> courseList = univCoursesList.getObject();
		Collections.sort(courseList, new CourseComparator());
		return courseList;
	}

	private boolean UpdateSemCourses() {
		CurriculumDAO cDao = new CurriculumDAO(getSessionORMInterface());
		cDao.clearMandatoryCourses(currModel.getObject(), semesterNo);
		cDao.clearOptionalCourses(currModel.getObject(), semesterNo);
		CourseListPacker clp = new CourseListPacker(hiddenCourseList);

		List<Courses> manCourses = clp.getMandatoryCourses();
		for (Courses man : manCourses) {
			int choiceSlots = clp.getNumOptionalCourses();
			for (int i = 0; i < choiceSlots; i++) {
				if (clp.getOptionalCourses(i).contains(man)) {
					return false;
				}
			}
		}

		cDao.addMandatoryCourse(currModel.getObject(), clp
				.getMandatoryCourses(), semesterNo);
		int choiceSlots = clp.getNumOptionalCourses();
		for (int i = 0; i < choiceSlots; i++) {
			cDao.addElectiveChoices(currModel.getObject(), clp
					.getOptionalCourses(i), semesterNo);
		}
		return true;
	}

	private class PrevButton extends Button {
		public PrevButton(String id) {
			super(id);
		}

		@Override
		public void onSubmit() {
			if (!UpdateSemCourses()) {
				setErrorMessage("The same course cannot be present in both mandatory and elective course list.");
				return;
			}
			PageParameters params = new PageParameters();
			params.put("0", currModel.getObject().getCurriculaId().toString());
			params.put("1", Integer.toString(semesterNo - 1));
			WebPage page = new CurriculaEditor(params);
			setResponsePage(page);
		}

		@Override
		public boolean isVisible() {
			if (semesterNo == 0)
				return false;
			return true;
		}

		private static final long serialVersionUID = -8661592647875717957L;
	}

	private class NextButton extends Button {
		public NextButton(String id) {
			super(id);
		}

		@Override
		public void onSubmit() {
			log.debug("Hidden Course List = " + hiddenCourseList);
			if (!UpdateSemCourses()) {
				setErrorMessage("The same course cannot be present in both mandatory and elective course list.");
				return;
			}
			PageParameters params = new PageParameters();
			params.put("0", currModel.getObject().getCurriculaId().toString());
			params.put("1", Integer.toString(semesterNo + 1));
			WebPage page = new CurriculaEditor(params);
			setResponsePage(page);
		}

		@Override
		public boolean isVisible() {
			if (semesterNo == currModel.getObject().getTotalSemester() - 1)
				return false;
			return true;

		}

		private static final long serialVersionUID = -8661592647875717957L;
	}

	private class FinishButton extends Button {
		public FinishButton(String id) {
			super(id);
		}

		@Override
		public void onSubmit() {
			if (!UpdateSemCourses()) {
				setErrorMessage("The same course cannot be present in both mandatory and elective course list.");
				return;
			}
			PageParameters params = new PageParameters();
			params.put("0", Integer.toString(currModel.getObject()
					.getCurriculaId()));
			setResponsePage(CurriculaSummary.class, params);
		}

		private static final long serialVersionUID = -8661592647875717957L;
	}

	public void setHiddenCourseList(String hiddenCourseList) {
		this.hiddenCourseList = hiddenCourseList;
	}

	public String getHiddenCourseList() {
		CurriculumDAO cDao = new CurriculumDAO(getSessionORMInterface());
		CourseListPacker clp = new CourseListPacker(cDao.getMandatoryCourses(
				currModel.getObject(), semesterNo));
		List<List<Courses>> courseList = cDao.getOptionalCourses(currModel
				.getObject(), semesterNo);
		for (List<Courses> c : courseList) {
			clp.addOptionalCourses(c);
		}
		hiddenCourseList = clp.getCourseString();
		return hiddenCourseList;
	}

	private int semesterNo = 0;
	private String hiddenCourseList = "";
	private IModel<Curricula> currModel = null;
	private CayenneList<Courses> univCoursesList = null;
	private IModel<Universities> univModel = null;
	private IModel<Departments> deptModel = null;

}
